package com.bieber.server.remote;

import com.bieber.common.Node;
import com.bieber.server.config.ServerConfig;
import com.bieber.server.executor.NamedThreadFactory;
import com.bieber.server.netty.handler.Decoder;
import com.bieber.server.netty.handler.Encoder;
import com.bieber.server.netty.handler.NettyHandler;
import com.bieber.server.pack.FilePackage;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;

import java.net.InetSocketAddress;

/**
 * Created by bieber on 2015/8/20.
 */
public class Client {

    private Node node;

    private ServerConfig config;

    private Bootstrap bootstrap;

    private Channel channel;

    private volatile boolean running;

    public Client(ServerConfig config,Node node){
        this.node = node;
        this.config = config;
        bootstrap = new Bootstrap();
    }

    public boolean isAvailable(){
        return node.isAvailable()&&channel.isActive();
    }

    public void initialize(){
        check();
        EventLoopGroup  bossGroup = new NioEventLoopGroup(1,new NamedThreadFactory("NETTY-CLIENT-BOSS-GROUP"));
        bootstrap.group(bossGroup).channel(NioSocketChannel.class)
                .option(ChannelOption.SO_REUSEADDR, true)
                .option(ChannelOption.SO_KEEPALIVE, false)
                .option(ChannelOption.SO_SNDBUF, config.getServerSocketSndBufSize())
                .option(ChannelOption.SO_RCVBUF, config.getServerSocketRcvBufSize())
                .handler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel ch) throws Exception {
                        ch.pipeline().addLast("decoder", new Decoder(config))
                                .addLast("encoder", new Encoder(config))
                                .addLast("handler", new NettyHandler());
                    }
                });
    }

    private void check(){
        if(running){
            throw new IllegalStateException("Client had running....");
        }
    }

    public void start(){
        check();
        running=true;
        try {
            channel = bootstrap.connect(new InetSocketAddress(node.getHost(), node.getPort())).sync().channel();
        } catch (InterruptedException e) {
            throw new RuntimeException("failed to connect remote server "+channel.remoteAddress(),e);
        }
      /*  try {
            future.sync();
        } catch (InterruptedException e) {
            throw new RuntimeException("failed to connect remote server "+channel.remoteAddress(),e);
        }*/
    }

    public void write(FilePackage filePackage){
        channel.writeAndFlush(filePackage);
    }

    public void stop(){
        channel.close();
        running=false;
    }




}

